/********************************************************************************
  DESCRIPTION OF THE FILE HERE
********************************************************************************/

#include "logger.h"
#include "common.h"

#include "pool.h"
#include <pthread.h>
#include <semaphore.h>

typedef struct SLogger {  
  ptrPool pool;
  long long int lapse; /* the interval every which to take a stamp */
  FILE * logfile;

  /* semaforo utilizzato per svegliarsi periodicamente */
  sem_t time_sem;

  bool enabled;
  pthread_t pt;
} Logger;

static void * threadbody(void * arg){
  ptrLogger logger = (ptrLogger) arg;
  struct timespec ts;
  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
  /* cleanup is not dealt */
  /* pthread_cleanup_push(cleanup_fun, arg); */
  while(true){
    throw_cond_error((clock_gettime(CLOCK_REALTIME, &ts) < 0),
		     "threadbody",
		     "impossible to get the real time from the system"
		     );
    /* some time is passing here but I can't help it */
    ts.tv_sec += logger->lapse / SEC;
    ts.tv_nsec += logger->lapse % SEC;
    /* nobody but the scheduler self will wake me up (after lapse secs) */
    sem_timedwait(&logger->time_sem, &ts);
    Pool_fprintfStatistics(logger->pool, logger->logfile);
  }
  /* pthread_cleanup_pop(0); */
  return NULL;
}

static void Logger_init(ptrLogger logger, ptrPool pool, long long int lapse, char * filename){
  logger->pool = pool;
  logger->enabled = true;

  sem_init(&logger->time_sem, 0, 0);
  logger->logfile = fopen(filename, "w");
  /* if an error occurred, try again */
  if (logger->logfile == NULL) logger->logfile = fopen(filename, "w");
  /* if another error occurred, just unable logging */
  if (logger->logfile == NULL){
    throw_msg("error while opening the specified file. Logging will be unabled.");
    perror("\t-->");
    logger->enabled = false;
  }
}

ptrLogger Logger_create(ptrPool pool, long long int lapse, char * filename){
  ptrLogger logger = new(Logger);
  Logger_init(logger, pool, lapse, filename);
  return logger;
}

void Logger_start(ptrLogger logger){
  if (logger->enabled){
    pthread_create(&logger->pt, NULL, threadbody, (void *) logger);
  }
}

#ifdef DEBUG
void Logger_printf (ptrLogger logger){
  /* BLA, BLA, BLA */
}
#endif /* DEBUG */

static void Logger_deinit(ptrLogger logger){
  /* it would be dangerous to destroy the thread pool */
  sem_destroy(&logger->time_sem);
  pthread_cancel(logger->pt);
  if (fclose(logger->logfile) != 0)
    perror("error while closing the log file");
};

void Logger_destroy(ptrLogger logger){
  if (logger != NULL){
    Logger_deinit(logger);
    delete(logger);
  }
}
